package com.yzy.fly.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONPObject;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonContainer;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.alibaba.fastjson.support.spring.MappingFastJsonValue;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.yzy.fly.api.function.response.entity.FlyApiResponseEntity;
import com.yzy.fly.api.function.response.fastJsonView.FastJsonViewResponseBodyAdvice;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Fastjson for Spring MVC Converter.
 * <p>
 * Compatible Spring MVC version 3.2+
 *
 * @author VictorZeng
 * @see AbstractHttpMessageConverter
 * @see GenericHttpMessageConverter
 * @since 1.2.10
 * <p>
 * <p>
 * <p>
 * Supported return type:
 * </p>
 * Simple object: Object
 * <p>
 * <p>
 * With property filter :FastJsonContainer[Object]
 * </p>
 * <p>
 * Jsonp :MappingFastJsonValue[Object]
 * </p>
 * Jsonp with property fter: MappingFastJsonValue[FastJsonContainer[Object]]
 */

public class FlyFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {

    private boolean setLengthError = false;

    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        ByteArrayOutputStream outnew = new ByteArrayOutputStream();
        try {
            HttpHeaders headers = outputMessage.getHeaders();
//            if (headers.containsKey("Content-Disposition")) {
//                List<String> list = headers.get("Content-Disposition");
//
//                Optional<String> first = list.stream().filter(l -> l.contains("attachment; filename=")).findFirst();
//                if (first.isPresent()) {
//                    return;
//                }
//            }
            FastJsonConfig fastJsonConfig = getFastJsonConfig();
            //获取全局配置的filter
            SerializeFilter[] globalFilters = fastJsonConfig.getSerializeFilters();
            List<SerializeFilter> allFilters = new ArrayList<SerializeFilter>(Arrays.asList(globalFilters));

            boolean isJsonp = false;
            //不知道为什么会有这行代码， 但是为了保持和原来的行为一致，还是保留下来
            Object value = strangeCodeForJackson(object);

            if (value instanceof FlyApiResponseEntity) {
                FlyApiResponseEntity response = (FlyApiResponseEntity)value;
                Object data = response.getData();
                if (data instanceof FastJsonViewResponseBodyAdvice.FastJsonContainer) {
                    FastJsonViewResponseBodyAdvice.FastJsonContainer fastJsonContainer = (FastJsonViewResponseBodyAdvice.FastJsonContainer) data;
                    PropertyPreFilters filters = fastJsonContainer.getFilters();
                    allFilters.addAll(filters.getFilters());
                    data = fastJsonContainer.getValue();
                } else if (data instanceof FastJsonContainer) {
                    FastJsonContainer fastJsonContainer = (FastJsonContainer) data;
                    PropertyPreFilters filters = fastJsonContainer.getFilters();
                    allFilters.addAll(filters.getFilters());
                    data = fastJsonContainer.getValue();
                }
                response.setData(data);
            } else if (value instanceof FastJsonViewResponseBodyAdvice.FastJsonContainer) {
                FastJsonViewResponseBodyAdvice.FastJsonContainer fastJsonContainer = (FastJsonViewResponseBodyAdvice.FastJsonContainer) value;
                PropertyPreFilters filters = fastJsonContainer.getFilters();
                allFilters.addAll(filters.getFilters());
                value = fastJsonContainer.getValue();
            } else if (value instanceof FastJsonContainer) {
                FastJsonContainer fastJsonContainer = (FastJsonContainer) value;
                PropertyPreFilters filters = fastJsonContainer.getFilters();
                allFilters.addAll(filters.getFilters());
                value = fastJsonContainer.getValue();
            }
            //revise 2017-10-23 ,
            // 保持原有的MappingFastJsonValue对象的contentType不做修改 保持旧版兼容。
            // 但是新的JSONPObject将返回标准的contentType：application/javascript ，不对是否有function进行判断
            if (value instanceof MappingFastJsonValue) {
                if (!StringUtils.isEmpty(((MappingFastJsonValue) value).getJsonpFunction())) {
                    isJsonp = true;
                }
            } else if (value instanceof JSONPObject) {
                isJsonp = true;
            }

            int len = JSON.writeJSONStringWithFastJsonConfig(outnew, //
                    fastJsonConfig.getCharset(), //
                    value, //
                    fastJsonConfig.getSerializeConfig(), //
                    //fastJsonConfig.getSerializeFilters(), //
                    allFilters.toArray(new SerializeFilter[allFilters.size()]),
                    fastJsonConfig.getDateFormat(), //
                    JSON.DEFAULT_GENERATE_FEATURE, //
                    fastJsonConfig.getSerializerFeatures());

            if (isJsonp) {
                headers.setContentType(APPLICATION_JAVASCRIPT);
            }

            if (fastJsonConfig.isWriteContentLength() && !setLengthError) {
                try {
                    headers.setContentLength(len);
                } catch (UnsupportedOperationException ex) {
                    // skip
                    setLengthError = true;
                }
            }
            outnew.writeTo(outputMessage.getBody());

        } catch (JSONException ex) {
            throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
        } finally {
            outnew.close();
        }
    }

    private Object strangeCodeForJackson(Object obj) {
        if (obj != null) {
            String className = obj.getClass().getName();
            if ("com.fasterxml.jackson.databind.node.ObjectNode".equals(className)) {
                return obj.toString();
            }
        }
        return obj;
    }

}
